
<!DOCTYPE HTML>
<html lang="" >
    <head>
        <title>GreenDao源码分析 · GitBook</title>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="generator" content="GitBook 3.2.0">
        
        
        
    
    <link rel="stylesheet" href="gitbook/style.css">

    
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-highlight/website.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-search/search.css">
                
            
                
                <link rel="stylesheet" href="gitbook/gitbook-plugin-fontsettings/website.css">
                
            
        

    

    
        
    
        
    
        
    
        
    
        
    
        
    

        
    
    
    <meta name="HandheldFriendly" content="true"/>
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon-precomposed" sizes="152x152" href="gitbook/images/apple-touch-icon-precomposed-152.png">
    <link rel="shortcut icon" href="gitbook/images/favicon.ico" type="image/x-icon">

    
    
    <link rel="prev" href="GreenDao使用.html" />
    

    </head>
    <body>
        
<div class="book">
    <div class="book-summary">
        
            
<div id="book-search-input" role="search">
    <input type="text" placeholder="Type to search" />
</div>

            
                <nav role="navigation">
                


<ul class="summary">
    
    

    

    
        
        
    
        <li class="chapter " data-level="1.1" data-path="./">
            
                <a href="./">
            
                    
                    Introduction
            
                </a>
            

            
        </li>
    
        <li class="chapter " data-level="1.2" data-path="GreenDao使用.html">
            
                <a href="GreenDao使用.html">
            
                    
                    GreenDao使用
            
                </a>
            

            
        </li>
    
        <li class="chapter active" data-level="1.3" data-path="GreenDao源码分析.html">
            
                <a href="GreenDao源码分析.html">
            
                    
                    GreenDao源码分析
            
                </a>
            

            
        </li>
    

    

    <li class="divider"></li>

    <li>
        <a href="https://www.gitbook.com" target="blank" class="gitbook-link">
            Published with GitBook
        </a>
    </li>
</ul>


                </nav>
            
        
    </div>

    <div class="book-body">
        
            <div class="body-inner">
                
                    

<div class="book-header" role="navigation">
    

    <!-- Title -->
    <h1>
        <i class="fa fa-circle-o-notch fa-spin"></i>
        <a href="." >GreenDao源码分析</a>
    </h1>
</div>




                    <div class="page-wrapper" tabindex="-1" role="main">
                        <div class="page-inner">
                            
<div id="book-search-results">
    <div class="search-noresults">
    
                                <section class="normal markdown-section">
                                
                                <p>DaoMaster&#x5185;&#x90E8;&#x6709;&#x4E00;&#x4E2A;OpenHelper&#x7C7B;&#xFF0C;&#x8D1F;&#x8D23;&#x521B;&#x5EFA;&#x6570;&#x636E;&#x5E93;</p><pre><code class="lang-java">DaoMaster.DevOpenHelper devOpenHelper = <span class="hljs-keyword">new</span> DaoMaster.DevOpenHelper(context, DB_NAME);</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AbstractDaoMaster</span> </span>{
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> Database db;
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> schemaVersion;
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> Map&lt;Class&lt;? extends AbstractDao&lt;?, ?&gt;&gt;, DaoConfig&gt; daoConfigMap;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AbstractDaoMaster</span><span class="hljs-params">(Database db, <span class="hljs-keyword">int</span> schemaVersion)</span> </span>{
        <span class="hljs-keyword">this</span>.db = db;
        <span class="hljs-keyword">this</span>.schemaVersion = schemaVersion;

        daoConfigMap = <span class="hljs-keyword">new</span> HashMap&lt;Class&lt;? extends AbstractDao&lt;?, ?&gt;&gt;, DaoConfig&gt;();
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">registerDaoClass</span><span class="hljs-params">(Class&lt;? extends AbstractDao&lt;?, ?&gt;&gt; daoClass)</span> </span>{
        DaoConfig daoConfig = <span class="hljs-keyword">new</span> DaoConfig(db, daoClass);<span class="hljs-comment">//&#x521B;&#x5EFA;DaoConfig</span>
        daoConfigMap.put(daoClass, daoConfig);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getSchemaVersion</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> schemaVersion;
    }

    <span class="hljs-comment">/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Database <span class="hljs-title">getDatabase</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> db;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> AbstractDaoSession <span class="hljs-title">newSession</span><span class="hljs-params">()</span></span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> AbstractDaoSession <span class="hljs-title">newSession</span><span class="hljs-params">(IdentityScopeType type)</span></span>;
}
</code></pre>
<pre><code class="lang-java"><span class="hljs-keyword">package</span> com.malinkang.sqlite;

<span class="hljs-keyword">import</span> android.content.Context;
<span class="hljs-keyword">import</span> android.database.sqlite.SQLiteDatabase;
<span class="hljs-keyword">import</span> android.database.sqlite.SQLiteDatabase.CursorFactory;
<span class="hljs-keyword">import</span> android.util.Log;

<span class="hljs-keyword">import</span> org.greenrobot.greendao.AbstractDaoMaster;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.database.StandardDatabase;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.database.Database;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.database.DatabaseOpenHelper;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.identityscope.IdentityScopeType;


<span class="hljs-comment">// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.</span>
<span class="hljs-comment">/**
 * Master of DAO (schema version 1): knows all DAOs.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DaoMaster</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbstractDaoMaster</span> </span>{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> SCHEMA_VERSION = <span class="hljs-number">1</span>;

    <span class="hljs-comment">/** Creates underlying database table using DAOs. */</span>
    <span class="hljs-comment">//&#x8C03;&#x7528;&#x6BCF;&#x4E2A;dao&#x7684;createTable&#x65B9;&#x6CD5;&#x6765;&#x521B;&#x5EFA;&#x8868;</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">createAllTables</span><span class="hljs-params">(Database db, <span class="hljs-keyword">boolean</span> ifNotExists)</span> </span>{
        CustomerDao.createTable(db, ifNotExists);
        OrderDao.createTable(db, ifNotExists);
        StudentDao.createTable(db, ifNotExists);
    }

    <span class="hljs-comment">/** Drops underlying database table using DAOs. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dropAllTables</span><span class="hljs-params">(Database db, <span class="hljs-keyword">boolean</span> ifExists)</span> </span>{
        CustomerDao.dropTable(db, ifExists);
        OrderDao.dropTable(db, ifExists);
        StudentDao.dropTable(db, ifExists);
    }

    <span class="hljs-comment">/**
     * WARNING: Drops all table on Upgrade! Use only during development.
     * Convenience method using a {<span class="hljs-doctag">@link</span> DevOpenHelper}.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> DaoSession <span class="hljs-title">newDevSession</span><span class="hljs-params">(Context context, String name)</span> </span>{
        Database db = <span class="hljs-keyword">new</span> DevOpenHelper(context, name).getWritableDb();
        DaoMaster daoMaster = <span class="hljs-keyword">new</span> DaoMaster(db);
        <span class="hljs-keyword">return</span> daoMaster.newSession();
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DaoMaster</span><span class="hljs-params">(SQLiteDatabase db)</span> </span>{
        <span class="hljs-keyword">this</span>(<span class="hljs-keyword">new</span> StandardDatabase(db));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DaoMaster</span><span class="hljs-params">(Database db)</span> </span>{
        <span class="hljs-keyword">super</span>(db, SCHEMA_VERSION);
        registerDaoClass(CustomerDao.class);
        registerDaoClass(OrderDao.class);
        registerDaoClass(StudentDao.class);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DaoSession <span class="hljs-title">newSession</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DaoSession(db, IdentityScopeType.Session, daoConfigMap);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DaoSession <span class="hljs-title">newSession</span><span class="hljs-params">(IdentityScopeType type)</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DaoSession(db, type, daoConfigMap);
    }

    <span class="hljs-comment">/**
     * Calls {<span class="hljs-doctag">@link</span> #createAllTables(Database, boolean)} in {<span class="hljs-doctag">@link</span> #onCreate(Database)} -
     */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OpenHelper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">DatabaseOpenHelper</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OpenHelper</span><span class="hljs-params">(Context context, String name)</span> </span>{
            <span class="hljs-keyword">super</span>(context, name, SCHEMA_VERSION);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OpenHelper</span><span class="hljs-params">(Context context, String name, CursorFactory factory)</span> </span>{
            <span class="hljs-keyword">super</span>(context, name, factory, SCHEMA_VERSION);
        }

        <span class="hljs-meta">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Database db)</span> </span>{
            Log.i(<span class="hljs-string">&quot;greenDAO&quot;</span>, <span class="hljs-string">&quot;Creating tables for schema version &quot;</span> + SCHEMA_VERSION);
            createAllTables(db, <span class="hljs-keyword">false</span>);<span class="hljs-comment">//&#x521B;&#x5EFA;&#x6240;&#x6709;&#x7684;&#x8868;</span>
        }
    }

    <span class="hljs-comment">/** WARNING: Drops all table on Upgrade! Use only during development. */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DevOpenHelper</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">OpenHelper</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DevOpenHelper</span><span class="hljs-params">(Context context, String name)</span> </span>{
            <span class="hljs-keyword">super</span>(context, name);
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DevOpenHelper</span><span class="hljs-params">(Context context, String name, CursorFactory factory)</span> </span>{
            <span class="hljs-keyword">super</span>(context, name, factory);
        }

        <span class="hljs-meta">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onUpgrade</span><span class="hljs-params">(Database db, <span class="hljs-keyword">int</span> oldVersion, <span class="hljs-keyword">int</span> newVersion)</span> </span>{
            Log.i(<span class="hljs-string">&quot;greenDAO&quot;</span>, <span class="hljs-string">&quot;Upgrading schema from version &quot;</span> + oldVersion + <span class="hljs-string">&quot; to &quot;</span> + newVersion + <span class="hljs-string">&quot; by dropping all tables&quot;</span>);
            dropAllTables(db, <span class="hljs-keyword">true</span>);
            onCreate(db);
        }
    }

}
</code></pre>
<p>DaoConfig&#x901A;&#x8FC7;&#x53CD;&#x5C04;&#x83B7;&#x53D6;&#x8868;&#x540D;&#x548C;&#x6240;&#x6709;&#x5217;&#x540D;&#x3002;</p><pre><code class="lang-java"><span class="hljs-comment">/**
 * Internal class used by greenDAO. DaoConfig stores essential data for DAOs, and is hold by AbstractDaoMaster. This
 * class will retrieve the required information from the DAO classes.
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DaoConfig</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Cloneable</span> </span>{

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> Database db;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> String tablename;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> Property[] properties;

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> String[] allColumns;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> String[] pkColumns;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> String[] nonPkColumns;

    <span class="hljs-comment">/** Single property PK or null if there&apos;s no PK or a multi property PK. */</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> Property pkProperty;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> keyIsNumeric;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> TableStatements statements;

    <span class="hljs-keyword">private</span> IdentityScope&lt;?, ?&gt; identityScope;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DaoConfig</span><span class="hljs-params">(Database db, Class&lt;? extends AbstractDao&lt;?, ?&gt;&gt; daoClass)</span> </span>{
        <span class="hljs-keyword">this</span>.db = db;
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">this</span>.tablename = (String) daoClass.getField(<span class="hljs-string">&quot;TABLENAME&quot;</span>).get(<span class="hljs-keyword">null</span>);
            Property[] properties = reflectProperties(daoClass);
            <span class="hljs-keyword">this</span>.properties = properties;

            allColumns = <span class="hljs-keyword">new</span> String[properties.length];

            List&lt;String&gt; pkColumnList = <span class="hljs-keyword">new</span> ArrayList&lt;String&gt;();
            List&lt;String&gt; nonPkColumnList = <span class="hljs-keyword">new</span> ArrayList&lt;String&gt;();
            Property lastPkProperty = <span class="hljs-keyword">null</span>;
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; properties.length; i++) {
                Property property = properties[i];
                String name = property.columnName;
                allColumns[i] = name;
                <span class="hljs-keyword">if</span> (property.primaryKey) {
                    pkColumnList.add(name);
                    lastPkProperty = property;
                } <span class="hljs-keyword">else</span> {
                    nonPkColumnList.add(name);
                }
            }
            String[] nonPkColumnsArray = <span class="hljs-keyword">new</span> String[nonPkColumnList.size()];
            nonPkColumns = nonPkColumnList.toArray(nonPkColumnsArray);
            String[] pkColumnsArray = <span class="hljs-keyword">new</span> String[pkColumnList.size()];
            pkColumns = pkColumnList.toArray(pkColumnsArray);

            pkProperty = pkColumns.length == <span class="hljs-number">1</span> ? lastPkProperty : <span class="hljs-keyword">null</span>;
            statements = <span class="hljs-keyword">new</span> TableStatements(db, tablename, allColumns, pkColumns);<span class="hljs-comment">//</span>

            <span class="hljs-keyword">if</span> (pkProperty != <span class="hljs-keyword">null</span>) {
                Class&lt;?&gt; type = pkProperty.type;
                keyIsNumeric = type.equals(<span class="hljs-keyword">long</span>.class) || type.equals(Long.class) || type.equals(<span class="hljs-keyword">int</span>.class)
                        || type.equals(Integer.class) || type.equals(<span class="hljs-keyword">short</span>.class) || type.equals(Short.class)
                        || type.equals(<span class="hljs-keyword">byte</span>.class) || type.equals(Byte.class);
            } <span class="hljs-keyword">else</span> {
                keyIsNumeric = <span class="hljs-keyword">false</span>;
            }

        } <span class="hljs-keyword">catch</span> (Exception e) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Could not init DAOConfig&quot;</span>, e);
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> Property[] reflectProperties(Class&lt;? extends AbstractDao&lt;?, ?&gt;&gt; daoClass)
            <span class="hljs-keyword">throws</span> ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
        Class&lt;?&gt; propertiesClass = Class.forName(daoClass.getName() + <span class="hljs-string">&quot;$Properties&quot;</span>);
        Field[] fields = propertiesClass.getDeclaredFields();

        ArrayList&lt;Property&gt; propertyList = <span class="hljs-keyword">new</span> ArrayList&lt;Property&gt;();
        <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> modifierMask = Modifier.STATIC | Modifier.PUBLIC;
        <span class="hljs-keyword">for</span> (Field field : fields) {
            <span class="hljs-comment">// There might be other fields introduced by some tools, just ignore them (see issue #28)</span>
            <span class="hljs-keyword">if</span> ((field.getModifiers() &amp; modifierMask) == modifierMask) {
                Object fieldValue = field.get(<span class="hljs-keyword">null</span>);
                <span class="hljs-keyword">if</span> (fieldValue <span class="hljs-keyword">instanceof</span> Property) {
                    propertyList.add((Property) fieldValue);
                }
            }
        }

        Property[] properties = <span class="hljs-keyword">new</span> Property[propertyList.size()];
        <span class="hljs-keyword">for</span> (Property property : propertyList) {
            <span class="hljs-keyword">if</span> (properties[property.ordinal] != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Duplicate property ordinals&quot;</span>);
            }
            properties[property.ordinal] = property;
        }
        <span class="hljs-keyword">return</span> properties;
    }

    <span class="hljs-comment">/** Does not copy identity scope. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">DaoConfig</span><span class="hljs-params">(DaoConfig source)</span> </span>{
        db = source.db;
        tablename = source.tablename;
        properties = source.properties;
        allColumns = source.allColumns;
        pkColumns = source.pkColumns;
        nonPkColumns = source.nonPkColumns;
        pkProperty = source.pkProperty;
        statements = source.statements;
        keyIsNumeric = source.keyIsNumeric;
    }

    <span class="hljs-comment">/** Does not copy identity scope. */</span>
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> DaoConfig <span class="hljs-title">clone</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DaoConfig(<span class="hljs-keyword">this</span>);
    }

    <span class="hljs-keyword">public</span> IdentityScope&lt;?, ?&gt; getIdentityScope() {
        <span class="hljs-keyword">return</span> identityScope;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setIdentityScope</span><span class="hljs-params">(IdentityScope&lt;?, ?&gt; identityScope)</span> </span>{
        <span class="hljs-keyword">this</span>.identityScope = identityScope;
    }

    <span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">&quot;rawtypes&quot;</span>)
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initIdentityScope</span><span class="hljs-params">(IdentityScopeType type)</span> </span>{
        <span class="hljs-keyword">if</span> (type == IdentityScopeType.None) {
            identityScope = <span class="hljs-keyword">null</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (type == IdentityScopeType.Session) {
            <span class="hljs-keyword">if</span> (keyIsNumeric) {
                identityScope = <span class="hljs-keyword">new</span> IdentityScopeLong();
            } <span class="hljs-keyword">else</span> {
                identityScope = <span class="hljs-keyword">new</span> IdentityScopeObject();
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">&quot;Unsupported type: &quot;</span> + type);
        }
    }

}
</code></pre>
<pre><code class="lang-java">
<span class="hljs-comment">/** Helper class to create SQL statements for specific tables (used by greenDAO internally). */</span>
<span class="hljs-comment">// Note: avoid locking while compiling any statement (accessing the db) to avoid deadlocks on lock-savvy DBs like</span>
<span class="hljs-comment">// SQLCipher.</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TableStatements</span> </span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Database db;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String tablename;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String[] allColumns;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String[] pkColumns;

    <span class="hljs-keyword">private</span> DatabaseStatement insertStatement;
    <span class="hljs-keyword">private</span> DatabaseStatement insertOrReplaceStatement;
    <span class="hljs-keyword">private</span> DatabaseStatement updateStatement;
    <span class="hljs-keyword">private</span> DatabaseStatement deleteStatement;
    <span class="hljs-keyword">private</span> DatabaseStatement countStatement;

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> String selectAll;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> String selectByKey;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> String selectByRowId;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">volatile</span> String selectKeys;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TableStatements</span><span class="hljs-params">(Database db, String tablename, String[] allColumns, String[] pkColumns)</span> </span>{
        <span class="hljs-keyword">this</span>.db = db;
        <span class="hljs-keyword">this</span>.tablename = tablename;
        <span class="hljs-keyword">this</span>.allColumns = allColumns;
        <span class="hljs-keyword">this</span>.pkColumns = pkColumns;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DatabaseStatement <span class="hljs-title">getInsertStatement</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (insertStatement == <span class="hljs-keyword">null</span>) {
            String sql = SqlUtils.createSqlInsert(<span class="hljs-string">&quot;INSERT INTO &quot;</span>, tablename, allColumns);
            DatabaseStatement newInsertStatement = db.compileStatement(sql);
            <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) {
                <span class="hljs-keyword">if</span> (insertStatement == <span class="hljs-keyword">null</span>) {
                    insertStatement = newInsertStatement;
                }
            }
            <span class="hljs-keyword">if</span> (insertStatement != newInsertStatement) {
                newInsertStatement.close();
            }
        }
        <span class="hljs-keyword">return</span> insertStatement;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DatabaseStatement <span class="hljs-title">getInsertOrReplaceStatement</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (insertOrReplaceStatement == <span class="hljs-keyword">null</span>) {
            String sql = SqlUtils.createSqlInsert(<span class="hljs-string">&quot;INSERT OR REPLACE INTO &quot;</span>, tablename, allColumns);<span class="hljs-comment">//&#x83B7;&#x53D6;sql&#x8BED;&#x53E5;</span>
            DatabaseStatement newInsertOrReplaceStatement = db.compileStatement(sql);<span class="hljs-comment">//&#x521B;&#x5EFA;DatabaseStatement&#x5BF9;&#x8C61;</span>
            <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) {
                <span class="hljs-keyword">if</span> (insertOrReplaceStatement == <span class="hljs-keyword">null</span>) {
                    insertOrReplaceStatement = newInsertOrReplaceStatement;
                }
            }
            <span class="hljs-keyword">if</span> (insertOrReplaceStatement != newInsertOrReplaceStatement) {
                newInsertOrReplaceStatement.close();
            }
        }
        <span class="hljs-keyword">return</span> insertOrReplaceStatement;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DatabaseStatement <span class="hljs-title">getDeleteStatement</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (deleteStatement == <span class="hljs-keyword">null</span>) {
            String sql = SqlUtils.createSqlDelete(tablename, pkColumns);
            DatabaseStatement newDeleteStatement = db.compileStatement(sql);
            <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) {
                <span class="hljs-keyword">if</span> (deleteStatement == <span class="hljs-keyword">null</span>) {
                    deleteStatement = newDeleteStatement;
                }
            }
            <span class="hljs-keyword">if</span> (deleteStatement != newDeleteStatement) {
                newDeleteStatement.close();
            }
        }
        <span class="hljs-keyword">return</span> deleteStatement;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DatabaseStatement <span class="hljs-title">getUpdateStatement</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (updateStatement == <span class="hljs-keyword">null</span>) {
            String sql = SqlUtils.createSqlUpdate(tablename, allColumns, pkColumns);
            DatabaseStatement newUpdateStatement = db.compileStatement(sql);
            <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) {
                <span class="hljs-keyword">if</span> (updateStatement == <span class="hljs-keyword">null</span>) {
                    updateStatement = newUpdateStatement;
                }
            }
            <span class="hljs-keyword">if</span> (updateStatement != newUpdateStatement) {
                newUpdateStatement.close();
            }
        }
        <span class="hljs-keyword">return</span> updateStatement;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> DatabaseStatement <span class="hljs-title">getCountStatement</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (countStatement == <span class="hljs-keyword">null</span>) {
            String sql = SqlUtils.createSqlCount(tablename);
            countStatement = db.compileStatement(sql);
        }
        <span class="hljs-keyword">return</span> countStatement;
    }

    <span class="hljs-comment">/** ends with an space to simplify appending to this string. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSelectAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (selectAll == <span class="hljs-keyword">null</span>) {
            selectAll = SqlUtils.createSqlSelect(tablename, <span class="hljs-string">&quot;T&quot;</span>, allColumns, <span class="hljs-keyword">false</span>);
        }
        <span class="hljs-keyword">return</span> selectAll;
    }

    <span class="hljs-comment">/** ends with an space to simplify appending to this string. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSelectKeys</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (selectKeys == <span class="hljs-keyword">null</span>) {
            selectKeys = SqlUtils.createSqlSelect(tablename, <span class="hljs-string">&quot;T&quot;</span>, pkColumns, <span class="hljs-keyword">false</span>);
        }
        <span class="hljs-keyword">return</span> selectKeys;
    }

    <span class="hljs-comment">// TODO precompile</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSelectByKey</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (selectByKey == <span class="hljs-keyword">null</span>) {
            StringBuilder builder = <span class="hljs-keyword">new</span> StringBuilder(getSelectAll());
            builder.append(<span class="hljs-string">&quot;WHERE &quot;</span>);
            SqlUtils.appendColumnsEqValue(builder, <span class="hljs-string">&quot;T&quot;</span>, pkColumns);
            selectByKey = builder.toString();
        }
        <span class="hljs-keyword">return</span> selectByKey;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getSelectByRowId</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (selectByRowId == <span class="hljs-keyword">null</span>) {
            selectByRowId = getSelectAll() + <span class="hljs-string">&quot;WHERE ROWID=?&quot;</span>;
        }
        <span class="hljs-keyword">return</span> selectByRowId;
    }

}</code></pre>
<p>AbstractDao</p><pre><code class="lang-java"><span class="hljs-comment">/*
 * Copyright (C) 2011-2016 Markus Junginger, greenrobot (http://greenrobot.de)
 *
 * Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */</span>

<span class="hljs-keyword">package</span> org.greenrobot.greendao;

<span class="hljs-keyword">import</span> android.database.CrossProcessCursor;
<span class="hljs-keyword">import</span> android.database.Cursor;
<span class="hljs-keyword">import</span> android.database.CursorWindow;
<span class="hljs-keyword">import</span> android.database.sqlite.SQLiteDatabase;
<span class="hljs-keyword">import</span> android.database.sqlite.SQLiteStatement;

<span class="hljs-keyword">import</span> org.greenrobot.greendao.database.Database;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.database.DatabaseStatement;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.identityscope.IdentityScope;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.identityscope.IdentityScopeLong;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.internal.DaoConfig;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.internal.FastCursor;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.internal.TableStatements;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.query.Query;
<span class="hljs-keyword">import</span> org.greenrobot.greendao.query.QueryBuilder;

<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.Collection;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-comment">/**
 * Base class for all DAOs: Implements entity operations like insert, load, delete, and query.
 * &lt;p/&gt;
 * This class is thread-safe.
 *
 * <span class="hljs-doctag">@param</span> &lt;T&gt; Entity type
 * <span class="hljs-doctag">@param</span> &lt;K&gt; Primary key (PK) type; use Void if entity does not have exactly one PK
 * <span class="hljs-doctag">@author</span> Markus
 */</span>
<span class="hljs-comment">/*
 * When operating on TX, statements, or identity scope the following locking order must be met to avoid deadlocks:
 * 
 * 1.) If not inside a TX already, begin a TX to acquire a DB connection (connection is to be handled like a lock)
 * 
 * 2.) The DatabaseStatement
 * 
 * 3.) identityScope
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AbstractDao</span>&lt;<span class="hljs-title">T</span>, <span class="hljs-title">K</span>&gt; </span>{
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> DaoConfig config;
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> Database db;
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> isStandardSQLite;
    <span class="hljs-keyword">protected</span> IdentityScope&lt;K, T&gt; identityScope;
    <span class="hljs-keyword">protected</span> IdentityScopeLong&lt;T&gt; identityScopeLong;
    <span class="hljs-keyword">protected</span> TableStatements statements;

    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> AbstractDaoSession session;
    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> pkOrdinal;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AbstractDao</span><span class="hljs-params">(DaoConfig config)</span> </span>{
        <span class="hljs-keyword">this</span>(config, <span class="hljs-keyword">null</span>);
    }

    <span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">&quot;unchecked&quot;</span>)
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AbstractDao</span><span class="hljs-params">(DaoConfig config, AbstractDaoSession daoSession)</span> </span>{
        <span class="hljs-keyword">this</span>.config = config;
        <span class="hljs-keyword">this</span>.session = daoSession;
        db = config.db;
        isStandardSQLite = db.getRawDatabase() <span class="hljs-keyword">instanceof</span> SQLiteDatabase;
        identityScope = (IdentityScope&lt;K, T&gt;) config.getIdentityScope();
        <span class="hljs-keyword">if</span> (identityScope <span class="hljs-keyword">instanceof</span> IdentityScopeLong) {
            identityScopeLong = (IdentityScopeLong&lt;T&gt;) identityScope;
        }
        statements = config.statements;
        pkOrdinal = config.pkProperty != <span class="hljs-keyword">null</span> ? config.pkProperty.ordinal : -<span class="hljs-number">1</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> AbstractDaoSession <span class="hljs-title">getSession</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> session;
    }

    <span class="hljs-function">TableStatements <span class="hljs-title">getStatements</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> config.statements;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getTablename</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> config.tablename;
    }

    <span class="hljs-keyword">public</span> Property[] getProperties() {
        <span class="hljs-keyword">return</span> config.properties;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Property <span class="hljs-title">getPkProperty</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> config.pkProperty;
    }

    <span class="hljs-keyword">public</span> String[] getAllColumns() {
        <span class="hljs-keyword">return</span> config.allColumns;
    }

    <span class="hljs-keyword">public</span> String[] getPkColumns() {
        <span class="hljs-keyword">return</span> config.pkColumns;
    }

    <span class="hljs-keyword">public</span> String[] getNonPkColumns() {
        <span class="hljs-keyword">return</span> config.nonPkColumns;
    }

    <span class="hljs-comment">/**
     * Loads the entity for the given PK.
     *
     * <span class="hljs-doctag">@param</span> key a PK value or null
     * <span class="hljs-doctag">@return</span> The entity or null, if no entity matched the PK value
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">load</span><span class="hljs-params">(K key)</span> </span>{
        assertSinglePk();
        <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
        }
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            T entity = identityScope.get(key);
            <span class="hljs-keyword">if</span> (entity != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">return</span> entity;
            }
        }
        String sql = statements.getSelectByKey();
        String[] keyArray = <span class="hljs-keyword">new</span> String[]{key.toString()};
        Cursor cursor = db.rawQuery(sql, keyArray);
        <span class="hljs-keyword">return</span> loadUniqueAndCloseCursor(cursor);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> T <span class="hljs-title">loadByRowId</span><span class="hljs-params">(<span class="hljs-keyword">long</span> rowId)</span> </span>{
        String[] idArray = <span class="hljs-keyword">new</span> String[]{Long.toString(rowId)};
        Cursor cursor = db.rawQuery(statements.getSelectByRowId(), idArray);
        <span class="hljs-keyword">return</span> loadUniqueAndCloseCursor(cursor);
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> T <span class="hljs-title">loadUniqueAndCloseCursor</span><span class="hljs-params">(Cursor cursor)</span> </span>{
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">return</span> loadUnique(cursor);
        } <span class="hljs-keyword">finally</span> {
            cursor.close();
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> T <span class="hljs-title">loadUnique</span><span class="hljs-params">(Cursor cursor)</span> </span>{
        <span class="hljs-keyword">boolean</span> available = cursor.moveToFirst();
        <span class="hljs-keyword">if</span> (!available) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!cursor.isLast()) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Expected unique result, but count was &quot;</span> + cursor.getCount());
        }
        <span class="hljs-keyword">return</span> loadCurrent(cursor, <span class="hljs-number">0</span>, <span class="hljs-keyword">true</span>);
    }

    <span class="hljs-comment">/** Loads all available entities from the database. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;T&gt; <span class="hljs-title">loadAll</span><span class="hljs-params">()</span> </span>{
        Cursor cursor = db.rawQuery(statements.getSelectAll(), <span class="hljs-keyword">null</span>);
        <span class="hljs-keyword">return</span> loadAllAndCloseCursor(cursor);
    }

    <span class="hljs-comment">/** Detaches an entity from the identity scope (session). Subsequent query results won&apos;t return this object. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">detach</span><span class="hljs-params">(T entity)</span> </span>{
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            K key = getKeyVerified(entity);
            <span class="hljs-keyword">return</span> identityScope.detach(key, entity);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
        }
    }

    <span class="hljs-comment">/**
     * Detaches all entities (of type T) from the identity scope (session). Subsequent query results won&apos;t return any
     * previously loaded objects.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">detachAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            identityScope.clear();
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> List&lt;T&gt; <span class="hljs-title">loadAllAndCloseCursor</span><span class="hljs-params">(Cursor cursor)</span> </span>{
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">return</span> loadAllFromCursor(cursor);
        } <span class="hljs-keyword">finally</span> {
            cursor.close();
        }
    }

    <span class="hljs-comment">/**
     * Inserts the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to insert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities)</span> </span>{
        insertInTx(entities, isEntityUpdateable());
    }

    <span class="hljs-comment">/**
     * Inserts the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to insert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertInTx</span><span class="hljs-params">(T... entities)</span> </span>{
        insertInTx(Arrays.asList(entities), isEntityUpdateable());
    }

    <span class="hljs-comment">/**
     * Inserts the given entities in the database using a transaction. The given entities will become tracked if the PK
     * is set.
     *
     * <span class="hljs-doctag">@param</span> entities      The entities to insert.
     * <span class="hljs-doctag">@param</span> setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve
     *                      performance.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities, <span class="hljs-keyword">boolean</span> setPrimaryKey)</span> </span>{
        DatabaseStatement stmt = statements.getInsertStatement();
        executeInsertInTx(stmt, entities, setPrimaryKey);
    }

    <span class="hljs-comment">/**
     * Inserts or replaces the given entities in the database using a transaction. The given entities will become
     * tracked if the PK is set.
     *
     * <span class="hljs-doctag">@param</span> entities      The entities to insert.
     * <span class="hljs-doctag">@param</span> setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve
     *                      performance.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertOrReplaceInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities, <span class="hljs-keyword">boolean</span> setPrimaryKey)</span> </span>{
        DatabaseStatement stmt = statements.getInsertOrReplaceStatement();
        executeInsertInTx(stmt, entities, setPrimaryKey);
    }

    <span class="hljs-comment">/**
     * Inserts or replaces the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to insert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertOrReplaceInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities)</span> </span>{
        insertOrReplaceInTx(entities, isEntityUpdateable());
    }

    <span class="hljs-comment">/**
     * Inserts or replaces the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to insert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertOrReplaceInTx</span><span class="hljs-params">(T... entities)</span> </span>{
        insertOrReplaceInTx(Arrays.asList(entities), isEntityUpdateable());
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">executeInsertInTx</span><span class="hljs-params">(DatabaseStatement stmt, Iterable&lt;T&gt; entities, <span class="hljs-keyword">boolean</span> setPrimaryKey)</span> </span>{
        db.beginTransaction();
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">synchronized</span> (stmt) {
                <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                    identityScope.lock();
                }
                <span class="hljs-keyword">try</span> {
                    <span class="hljs-keyword">if</span> (isStandardSQLite) {
                        SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
                        <span class="hljs-keyword">for</span> (T entity : entities) {
                            bindValues(rawStmt, entity);
                            <span class="hljs-keyword">if</span> (setPrimaryKey) {
                                <span class="hljs-keyword">long</span> rowId = rawStmt.executeInsert();
                                updateKeyAfterInsertAndAttach(entity, rowId, <span class="hljs-keyword">false</span>);
                            } <span class="hljs-keyword">else</span> {
                                rawStmt.execute();
                            }
                        }
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-keyword">for</span> (T entity : entities) {
                            bindValues(stmt, entity);
                            <span class="hljs-keyword">if</span> (setPrimaryKey) {
                                <span class="hljs-keyword">long</span> rowId = stmt.executeInsert();
                                updateKeyAfterInsertAndAttach(entity, rowId, <span class="hljs-keyword">false</span>);
                            } <span class="hljs-keyword">else</span> {
                                stmt.execute();
                            }
                        }
                    }
                } <span class="hljs-keyword">finally</span> {
                    <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                        identityScope.unlock();
                    }
                }
            }
            db.setTransactionSuccessful();
        } <span class="hljs-keyword">finally</span> {
            db.endTransaction();
        }
    }

    <span class="hljs-comment">/**
     * Insert an entity into the table associated with a concrete DAO.
     *
     * <span class="hljs-doctag">@return</span> row ID of newly inserted entity
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">insert</span><span class="hljs-params">(T entity)</span> </span>{
        <span class="hljs-keyword">return</span> executeInsert(entity, statements.getInsertStatement(), <span class="hljs-keyword">true</span>);
    }

    <span class="hljs-comment">/**
     * Insert an entity into the table associated with a concrete DAO &lt;b&gt;without&lt;/b&gt; setting key property.
     * &lt;p/&gt;
     * Warning: This may be faster, but the entity should not be used anymore. The entity also won&apos;t be attached to
     * identity scope.
     *
     * <span class="hljs-doctag">@return</span> row ID of newly inserted entity
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">insertWithoutSettingPk</span><span class="hljs-params">(T entity)</span> </span>{
        <span class="hljs-keyword">return</span> executeInsert(entity, statements.getInsertOrReplaceStatement(), <span class="hljs-keyword">false</span>);
    }

    <span class="hljs-comment">/**
     * Insert an entity into the table associated with a concrete DAO.
     *
     * <span class="hljs-doctag">@return</span> row ID of newly inserted entity
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">insertOrReplace</span><span class="hljs-params">(T entity)</span> </span>{
        <span class="hljs-keyword">return</span> executeInsert(entity, statements.getInsertOrReplaceStatement(), <span class="hljs-keyword">true</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> <span class="hljs-title">executeInsert</span><span class="hljs-params">(T entity, DatabaseStatement stmt, <span class="hljs-keyword">boolean</span> setKeyAndAttach)</span> </span>{
        <span class="hljs-keyword">long</span> rowId;
        <span class="hljs-keyword">if</span> (db.isDbLockedByCurrentThread()) {
            rowId = insertInsideTx(entity, stmt);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Do TX to acquire a connection before locking the stmt to avoid deadlocks</span>
            db.beginTransaction();
            <span class="hljs-keyword">try</span> {
                rowId = insertInsideTx(entity, stmt);
                db.setTransactionSuccessful();
            } <span class="hljs-keyword">finally</span> {
                db.endTransaction();
            }
        }
        <span class="hljs-keyword">if</span> (setKeyAndAttach) {
            updateKeyAfterInsertAndAttach(entity, rowId, <span class="hljs-keyword">true</span>);
        }
        <span class="hljs-keyword">return</span> rowId;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> <span class="hljs-title">insertInsideTx</span><span class="hljs-params">(T entity, DatabaseStatement stmt)</span> </span>{
        <span class="hljs-keyword">synchronized</span> (stmt) {
            <span class="hljs-keyword">if</span> (isStandardSQLite) {
                SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
                bindValues(rawStmt, entity);
                <span class="hljs-keyword">return</span> rawStmt.executeInsert();
            } <span class="hljs-keyword">else</span> {
                bindValues(stmt, entity);
                <span class="hljs-keyword">return</span> stmt.executeInsert();
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateKeyAfterInsertAndAttach</span><span class="hljs-params">(T entity, <span class="hljs-keyword">long</span> rowId, <span class="hljs-keyword">boolean</span> lock)</span> </span>{
        <span class="hljs-keyword">if</span> (rowId != -<span class="hljs-number">1</span>) {
            K key = updateKeyAfterInsert(entity, rowId);
            attachEntity(key, entity, lock);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// TODO When does this actually happen? Should we throw instead?</span>
            DaoLog.w(<span class="hljs-string">&quot;Could not insert row (executeInsert returned -1)&quot;</span>);
        }
    }

    <span class="hljs-comment">/** Reads all available rows from the given cursor and returns a list of entities. */</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> List&lt;T&gt; <span class="hljs-title">loadAllFromCursor</span><span class="hljs-params">(Cursor cursor)</span> </span>{
        <span class="hljs-keyword">int</span> count = cursor.getCount();
        <span class="hljs-keyword">if</span> (count == <span class="hljs-number">0</span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;T&gt;();
        }
        List&lt;T&gt; list = <span class="hljs-keyword">new</span> ArrayList&lt;T&gt;(count);
        CursorWindow window = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">boolean</span> useFastCursor = <span class="hljs-keyword">false</span>;
        <span class="hljs-keyword">if</span> (cursor <span class="hljs-keyword">instanceof</span> CrossProcessCursor) {
            window = ((CrossProcessCursor) cursor).getWindow();
            <span class="hljs-keyword">if</span> (window != <span class="hljs-keyword">null</span>) { <span class="hljs-comment">// E.g. Robolectric has no Window at this point</span>
                <span class="hljs-keyword">if</span> (window.getNumRows() == count) {
                    cursor = <span class="hljs-keyword">new</span> FastCursor(window);
                    useFastCursor = <span class="hljs-keyword">true</span>;
                } <span class="hljs-keyword">else</span> {
                    DaoLog.d(<span class="hljs-string">&quot;Window vs. result size: &quot;</span> + window.getNumRows() + <span class="hljs-string">&quot;/&quot;</span> + count);
                }
            }
        }

        <span class="hljs-keyword">if</span> (cursor.moveToFirst()) {
            <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                identityScope.lock();
                identityScope.reserveRoom(count);
            }

            <span class="hljs-keyword">try</span> {
                <span class="hljs-keyword">if</span> (!useFastCursor &amp;&amp; window != <span class="hljs-keyword">null</span> &amp;&amp; identityScope != <span class="hljs-keyword">null</span>) {
                    loadAllUnlockOnWindowBounds(cursor, window, list);
                } <span class="hljs-keyword">else</span> {
                    do {
                        list.add(loadCurrent(cursor, <span class="hljs-number">0</span>, <span class="hljs-keyword">false</span>));
                    } <span class="hljs-keyword">while</span> (cursor.moveToNext());
                }
            } <span class="hljs-keyword">finally</span> {
                <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                    identityScope.unlock();
                }
            }
        }
        <span class="hljs-keyword">return</span> list;
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">loadAllUnlockOnWindowBounds</span><span class="hljs-params">(Cursor cursor, CursorWindow window, List&lt;T&gt; list)</span> </span>{
        <span class="hljs-keyword">int</span> windowEnd = window.getStartPosition() + window.getNumRows();
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> row = <span class="hljs-number">0</span>; ; row++) {
            list.add(loadCurrent(cursor, <span class="hljs-number">0</span>, <span class="hljs-keyword">false</span>));
            row++;
            <span class="hljs-keyword">if</span> (row &gt;= windowEnd) {
                window = moveToNextUnlocked(cursor);
                <span class="hljs-keyword">if</span> (window == <span class="hljs-keyword">null</span>) {
                    <span class="hljs-keyword">break</span>;
                }
                windowEnd = window.getStartPosition() + window.getNumRows();
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">if</span> (!cursor.moveToNext()) {
                    <span class="hljs-keyword">break</span>;
                }
            }
        }
    }

    <span class="hljs-comment">/**
     * Unlock identityScope during cursor.moveToNext() when it is about to fill the window (needs a db connection):
     * We should not hold the lock while trying to acquire a db connection to avoid deadlocks.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> CursorWindow <span class="hljs-title">moveToNextUnlocked</span><span class="hljs-params">(Cursor cursor)</span> </span>{
        identityScope.unlock();
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">if</span> (cursor.moveToNext()) {
                <span class="hljs-keyword">return</span> ((CrossProcessCursor) cursor).getWindow();
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
            }
        } <span class="hljs-keyword">finally</span> {
            identityScope.lock();
        }
    }

    <span class="hljs-comment">/** Internal use only. Considers identity scope. */</span>
    <span class="hljs-function"><span class="hljs-keyword">final</span> <span class="hljs-keyword">protected</span> T <span class="hljs-title">loadCurrent</span><span class="hljs-params">(Cursor cursor, <span class="hljs-keyword">int</span> offset, <span class="hljs-keyword">boolean</span> lock)</span> </span>{
        <span class="hljs-keyword">if</span> (identityScopeLong != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">if</span> (offset != <span class="hljs-number">0</span>) {
                <span class="hljs-comment">// Occurs with deep loads (left outer joins)</span>
                <span class="hljs-keyword">if</span> (cursor.isNull(pkOrdinal + offset)) {
                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
                }
            }

            <span class="hljs-keyword">long</span> key = cursor.getLong(pkOrdinal + offset);
            T entity = lock ? identityScopeLong.get2(key) : identityScopeLong.get2NoLock(key);
            <span class="hljs-keyword">if</span> (entity != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">return</span> entity;
            } <span class="hljs-keyword">else</span> {
                entity = readEntity(cursor, offset);
                attachEntity(entity);
                <span class="hljs-keyword">if</span> (lock) {
                    identityScopeLong.put2(key, entity);
                } <span class="hljs-keyword">else</span> {
                    identityScopeLong.put2NoLock(key, entity);
                }
                <span class="hljs-keyword">return</span> entity;
            }
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            K key = readKey(cursor, offset);
            <span class="hljs-keyword">if</span> (offset != <span class="hljs-number">0</span> &amp;&amp; key == <span class="hljs-keyword">null</span>) {
                <span class="hljs-comment">// Occurs with deep loads (left outer joins)</span>
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
            }
            T entity = lock ? identityScope.get(key) : identityScope.getNoLock(key);
            <span class="hljs-keyword">if</span> (entity != <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">return</span> entity;
            } <span class="hljs-keyword">else</span> {
                entity = readEntity(cursor, offset);
                attachEntity(key, entity, lock);
                <span class="hljs-keyword">return</span> entity;
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Check offset, assume a value !=0 indicating a potential outer join, so check PK</span>
            <span class="hljs-keyword">if</span> (offset != <span class="hljs-number">0</span>) {
                K key = readKey(cursor, offset);
                <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
                    <span class="hljs-comment">// Occurs with deep loads (left outer joins)</span>
                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
                }
            }
            T entity = readEntity(cursor, offset);
            attachEntity(entity);
            <span class="hljs-keyword">return</span> entity;
        }
    }

    <span class="hljs-comment">/** Internal use only. Considers identity scope. */</span>
    <span class="hljs-keyword">final</span> <span class="hljs-keyword">protected</span> &lt;O&gt; <span class="hljs-function">O <span class="hljs-title">loadCurrentOther</span><span class="hljs-params">(AbstractDao&lt;O, ?&gt; dao, Cursor cursor, <span class="hljs-keyword">int</span> offset)</span> </span>{
        <span class="hljs-keyword">return</span> dao.loadCurrent(cursor, offset, <span class="hljs-comment">/* TODO check this */</span><span class="hljs-keyword">true</span>);
    }

    <span class="hljs-comment">/** A raw-style query where you can pass any WHERE clause and arguments. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;T&gt; <span class="hljs-title">queryRaw</span><span class="hljs-params">(String where, String... selectionArg)</span> </span>{
        Cursor cursor = db.rawQuery(statements.getSelectAll() + where, selectionArg);
        <span class="hljs-keyword">return</span> loadAllAndCloseCursor(cursor);
    }

    <span class="hljs-comment">/**
     * Creates a repeatable {<span class="hljs-doctag">@link</span> Query} object based on the given raw SQL where you can pass any WHERE clause and
     * arguments.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Query&lt;T&gt; <span class="hljs-title">queryRawCreate</span><span class="hljs-params">(String where, Object... selectionArg)</span> </span>{
        List&lt;Object&gt; argList = Arrays.asList(selectionArg);
        <span class="hljs-keyword">return</span> queryRawCreateListArgs(where, argList);
    }

    <span class="hljs-comment">/**
     * Creates a repeatable {<span class="hljs-doctag">@link</span> Query} object based on the given raw SQL where you can pass any WHERE clause and
     * arguments.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Query&lt;T&gt; <span class="hljs-title">queryRawCreateListArgs</span><span class="hljs-params">(String where, Collection&lt;Object&gt; selectionArg)</span> </span>{
        <span class="hljs-keyword">return</span> Query.internalCreate(<span class="hljs-keyword">this</span>, statements.getSelectAll() + where, selectionArg.toArray());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteAll</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// String sql = SqlUtils.createSqlDelete(config.tablename, null);</span>
        <span class="hljs-comment">// db.execSQL(sql);</span>

        db.execSQL(<span class="hljs-string">&quot;DELETE FROM &apos;&quot;</span> + config.tablename + <span class="hljs-string">&quot;&apos;&quot;</span>);
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            identityScope.clear();
        }
    }

    <span class="hljs-comment">/** Deletes the given entity from the database. Currently, only single value PK entities are supported. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">delete</span><span class="hljs-params">(T entity)</span> </span>{
        assertSinglePk();
        K key = getKeyVerified(entity);
        deleteByKey(key);
    }

    <span class="hljs-comment">/** Deletes an entity with the given PK from the database. Currently, only single value PK entities are supported. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteByKey</span><span class="hljs-params">(K key)</span> </span>{
        assertSinglePk();
        DatabaseStatement stmt = statements.getDeleteStatement();
        <span class="hljs-keyword">if</span> (db.isDbLockedByCurrentThread()) {
            <span class="hljs-keyword">synchronized</span> (stmt) {
                deleteByKeyInsideSynchronized(key, stmt);
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Do TX to acquire a connection before locking the stmt to avoid deadlocks</span>
            db.beginTransaction();
            <span class="hljs-keyword">try</span> {
                <span class="hljs-keyword">synchronized</span> (stmt) {
                    deleteByKeyInsideSynchronized(key, stmt);
                }
                db.setTransactionSuccessful();
            } <span class="hljs-keyword">finally</span> {
                db.endTransaction();
            }
        }
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
            identityScope.remove(key);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteByKeyInsideSynchronized</span><span class="hljs-params">(K key, DatabaseStatement stmt)</span> </span>{
        <span class="hljs-keyword">if</span> (key <span class="hljs-keyword">instanceof</span> Long) {
            stmt.bindLong(<span class="hljs-number">1</span>, (Long) key);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Cannot delete entity, key is null&quot;</span>);
        } <span class="hljs-keyword">else</span> {
            stmt.bindString(<span class="hljs-number">1</span>, key.toString());
        }
        stmt.execute();
    }

    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteInTxInternal</span><span class="hljs-params">(Iterable&lt;T&gt; entities, Iterable&lt;K&gt; keys)</span> </span>{
        assertSinglePk();
        DatabaseStatement stmt = statements.getDeleteStatement();
        List&lt;K&gt; keysToRemoveFromIdentityScope = <span class="hljs-keyword">null</span>;
        db.beginTransaction();
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">synchronized</span> (stmt) {
                <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                    identityScope.lock();
                    keysToRemoveFromIdentityScope = <span class="hljs-keyword">new</span> ArrayList&lt;K&gt;();
                }
                <span class="hljs-keyword">try</span> {
                    <span class="hljs-keyword">if</span> (entities != <span class="hljs-keyword">null</span>) {
                        <span class="hljs-keyword">for</span> (T entity : entities) {
                            K key = getKeyVerified(entity);
                            deleteByKeyInsideSynchronized(key, stmt);
                            <span class="hljs-keyword">if</span> (keysToRemoveFromIdentityScope != <span class="hljs-keyword">null</span>) {
                                keysToRemoveFromIdentityScope.add(key);
                            }
                        }
                    }
                    <span class="hljs-keyword">if</span> (keys != <span class="hljs-keyword">null</span>) {
                        <span class="hljs-keyword">for</span> (K key : keys) {
                            deleteByKeyInsideSynchronized(key, stmt);
                            <span class="hljs-keyword">if</span> (keysToRemoveFromIdentityScope != <span class="hljs-keyword">null</span>) {
                                keysToRemoveFromIdentityScope.add(key);
                            }
                        }
                    }
                } <span class="hljs-keyword">finally</span> {
                    <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                        identityScope.unlock();
                    }
                }
            }
            db.setTransactionSuccessful();
            <span class="hljs-keyword">if</span> (keysToRemoveFromIdentityScope != <span class="hljs-keyword">null</span> &amp;&amp; identityScope != <span class="hljs-keyword">null</span>) {
                identityScope.remove(keysToRemoveFromIdentityScope);
            }
        } <span class="hljs-keyword">finally</span> {
            db.endTransaction();
        }
    }

    <span class="hljs-comment">/**
     * Deletes the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to delete.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities)</span> </span>{
        deleteInTxInternal(entities, <span class="hljs-keyword">null</span>);
    }

    <span class="hljs-comment">/**
     * Deletes the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to delete.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteInTx</span><span class="hljs-params">(T... entities)</span> </span>{
        deleteInTxInternal(Arrays.asList(entities), <span class="hljs-keyword">null</span>);
    }

    <span class="hljs-comment">/**
     * Deletes all entities with the given keys in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> keys Keys of the entities to delete.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteByKeyInTx</span><span class="hljs-params">(Iterable&lt;K&gt; keys)</span> </span>{
        deleteInTxInternal(<span class="hljs-keyword">null</span>, keys);
    }

    <span class="hljs-comment">/**
     * Deletes all entities with the given keys in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> keys Keys of the entities to delete.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteByKeyInTx</span><span class="hljs-params">(K... keys)</span> </span>{
        deleteInTxInternal(<span class="hljs-keyword">null</span>, Arrays.asList(keys));
    }

    <span class="hljs-comment">/** Resets all locally changed properties of the entity by reloading the values from the database. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">refresh</span><span class="hljs-params">(T entity)</span> </span>{
        assertSinglePk();
        K key = getKeyVerified(entity);
        String sql = statements.getSelectByKey();
        String[] keyArray = <span class="hljs-keyword">new</span> String[]{key.toString()};
        Cursor cursor = db.rawQuery(sql, keyArray);
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">boolean</span> available = cursor.moveToFirst();
            <span class="hljs-keyword">if</span> (!available) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Entity does not exist in the database anymore: &quot;</span> + entity.getClass()
                        + <span class="hljs-string">&quot; with key &quot;</span> + key);
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!cursor.isLast()) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Expected unique result, but count was &quot;</span> + cursor.getCount());
            }
            readEntity(cursor, entity, <span class="hljs-number">0</span>);
            attachEntity(key, entity, <span class="hljs-keyword">true</span>);
        } <span class="hljs-keyword">finally</span> {
            cursor.close();
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">update</span><span class="hljs-params">(T entity)</span> </span>{
        assertSinglePk();
        DatabaseStatement stmt = statements.getUpdateStatement();
        <span class="hljs-keyword">if</span> (db.isDbLockedByCurrentThread()) {
            <span class="hljs-keyword">synchronized</span> (stmt) {
                <span class="hljs-keyword">if</span> (isStandardSQLite) {
                    updateInsideSynchronized(entity, (SQLiteStatement) stmt.getRawStatement(), <span class="hljs-keyword">true</span>);
                } <span class="hljs-keyword">else</span> {
                    updateInsideSynchronized(entity, stmt, <span class="hljs-keyword">true</span>);
                }
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-comment">// Do TX to acquire a connection before locking the stmt to avoid deadlocks</span>
            db.beginTransaction();
            <span class="hljs-keyword">try</span> {
                <span class="hljs-keyword">synchronized</span> (stmt) {
                    updateInsideSynchronized(entity, stmt, <span class="hljs-keyword">true</span>);
                }
                db.setTransactionSuccessful();
            } <span class="hljs-keyword">finally</span> {
                db.endTransaction();
            }
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> QueryBuilder&lt;T&gt; <span class="hljs-title">queryBuilder</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> QueryBuilder.internalCreate(<span class="hljs-keyword">this</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateInsideSynchronized</span><span class="hljs-params">(T entity, DatabaseStatement stmt, <span class="hljs-keyword">boolean</span> lock)</span> </span>{
        <span class="hljs-comment">// To do? Check if it&apos;s worth not to bind PKs here (performance).</span>
        bindValues(stmt, entity);
        <span class="hljs-keyword">int</span> index = config.allColumns.length + <span class="hljs-number">1</span>;
        K key = getKey(entity);
        <span class="hljs-keyword">if</span> (key <span class="hljs-keyword">instanceof</span> Long) {
            stmt.bindLong(index, (Long) key);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Cannot update entity without key - was it inserted before?&quot;</span>);
        } <span class="hljs-keyword">else</span> {
            stmt.bindString(index, key.toString());
        }
        stmt.execute();
        attachEntity(key, entity, lock);
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateInsideSynchronized</span><span class="hljs-params">(T entity, SQLiteStatement stmt, <span class="hljs-keyword">boolean</span> lock)</span> </span>{
        <span class="hljs-comment">// To do? Check if it&apos;s worth not to bind PKs here (performance).</span>
        bindValues(stmt, entity);
        <span class="hljs-keyword">int</span> index = config.allColumns.length + <span class="hljs-number">1</span>;
        K key = getKey(entity);
        <span class="hljs-keyword">if</span> (key <span class="hljs-keyword">instanceof</span> Long) {
            stmt.bindLong(index, (Long) key);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Cannot update entity without key - was it inserted before?&quot;</span>);
        } <span class="hljs-keyword">else</span> {
            stmt.bindString(index, key.toString());
        }
        stmt.execute();
        attachEntity(key, entity, lock);
    }

    <span class="hljs-comment">/**
     * Attaches the entity to the identity scope. Calls attachEntity(T entity).
     *
     * <span class="hljs-doctag">@param</span> key    Needed only for identity scope, pass null if there&apos;s none.
     * <span class="hljs-doctag">@param</span> entity The entitiy to attach
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">attachEntity</span><span class="hljs-params">(K key, T entity, <span class="hljs-keyword">boolean</span> lock)</span> </span>{
        attachEntity(entity);
        <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span> &amp;&amp; key != <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">if</span> (lock) {
                identityScope.put(key, entity);
            } <span class="hljs-keyword">else</span> {
                identityScope.putNoLock(key, entity);
            }
        }
    }

    <span class="hljs-comment">/**
     * Sub classes with relations additionally set the DaoMaster here. Must be called before the entity is attached to
     * the identity scope.
     *
     * <span class="hljs-doctag">@param</span> entity The entitiy to attach
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">attachEntity</span><span class="hljs-params">(T entity)</span> </span>{
    }

    <span class="hljs-comment">/**
     * Updates the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to insert.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateInTx</span><span class="hljs-params">(Iterable&lt;T&gt; entities)</span> </span>{
        DatabaseStatement stmt = statements.getUpdateStatement();
        db.beginTransaction();
        RuntimeException txEx = <span class="hljs-keyword">null</span>;
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">synchronized</span> (stmt) {
                <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                    identityScope.lock();
                }
                <span class="hljs-keyword">try</span> {
                    <span class="hljs-keyword">if</span> (isStandardSQLite) {
                        SQLiteStatement rawStmt = (SQLiteStatement) stmt.getRawStatement();
                        <span class="hljs-keyword">for</span> (T entity : entities) {
                            updateInsideSynchronized(entity, rawStmt, <span class="hljs-keyword">false</span>);
                        }
                    } <span class="hljs-keyword">else</span> {
                        <span class="hljs-keyword">for</span> (T entity : entities) {
                            updateInsideSynchronized(entity, stmt, <span class="hljs-keyword">false</span>);
                        }
                    }
                } <span class="hljs-keyword">finally</span> {
                    <span class="hljs-keyword">if</span> (identityScope != <span class="hljs-keyword">null</span>) {
                        identityScope.unlock();
                    }
                }
            }
            db.setTransactionSuccessful();
        } <span class="hljs-keyword">catch</span> (RuntimeException e) {
            txEx = e;
        } <span class="hljs-keyword">finally</span> {
            <span class="hljs-keyword">try</span> {
                db.endTransaction();
            } <span class="hljs-keyword">catch</span> (RuntimeException e) {
                <span class="hljs-keyword">if</span> (txEx != <span class="hljs-keyword">null</span>) {
                    DaoLog.w(<span class="hljs-string">&quot;Could not end transaction (rethrowing initial exception)&quot;</span>, e);
                    <span class="hljs-keyword">throw</span> txEx;
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">throw</span> e;
                }
            }
        }
    }

    <span class="hljs-comment">/**
     * Updates the given entities in the database using a transaction.
     *
     * <span class="hljs-doctag">@param</span> entities The entities to update.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">updateInTx</span><span class="hljs-params">(T... entities)</span> </span>{
        updateInTx(Arrays.asList(entities));
    }

    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">assertSinglePk</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (config.pkColumns.length != <span class="hljs-number">1</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-keyword">this</span> + <span class="hljs-string">&quot; (&quot;</span> + config.tablename + <span class="hljs-string">&quot;) does not have a single-column primary key&quot;</span>);
        }
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">long</span> <span class="hljs-title">count</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> statements.getCountStatement().simpleQueryForLong();
    }

    <span class="hljs-comment">/** See {<span class="hljs-doctag">@link</span> #getKey(Object)}, but guarantees that the returned key is never null (throws if null). */</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> K <span class="hljs-title">getKeyVerified</span><span class="hljs-params">(T entity)</span> </span>{
        K key = getKey(entity);
        <span class="hljs-keyword">if</span> (key == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">if</span> (entity == <span class="hljs-keyword">null</span>) {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NullPointerException(<span class="hljs-string">&quot;Entity may not be null&quot;</span>);
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> DaoException(<span class="hljs-string">&quot;Entity has no key&quot;</span>);
            }
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">return</span> key;
        }
    }

    <span class="hljs-comment">/** Gets the SQLiteDatabase for custom database access. Not needed for greenDAO entities. */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> Database <span class="hljs-title">getDatabase</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> db;
    }

    <span class="hljs-comment">/** Reads the values from the current position of the given cursor and returns a new entity. */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> T <span class="hljs-title">readEntity</span><span class="hljs-params">(Cursor cursor, <span class="hljs-keyword">int</span> offset)</span></span>;


    <span class="hljs-comment">/** Reads the key from the current position of the given cursor, or returns null if there&apos;s no single-value key. */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> K <span class="hljs-title">readKey</span><span class="hljs-params">(Cursor cursor, <span class="hljs-keyword">int</span> offset)</span></span>;

    <span class="hljs-comment">/** Reads the values from the current position of the given cursor into an existing entity. */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">readEntity</span><span class="hljs-params">(Cursor cursor, T entity, <span class="hljs-keyword">int</span> offset)</span></span>;

    <span class="hljs-comment">/** Binds the entity&apos;s values to the statement. Make sure to synchronize the statement outside of the method. */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">bindValues</span><span class="hljs-params">(DatabaseStatement stmt, T entity)</span></span>;

    <span class="hljs-comment">/**
     * Binds the entity&apos;s values to the statement. Make sure to synchronize the enclosing DatabaseStatement outside
     * of the method.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">bindValues</span><span class="hljs-params">(SQLiteStatement stmt, T entity)</span></span>;

    <span class="hljs-comment">/**
     * Updates the entity&apos;s key if possible (only for Long PKs currently). This method must always return the entity&apos;s
     * key regardless of whether the key existed before or not.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> K <span class="hljs-title">updateKeyAfterInsert</span><span class="hljs-params">(T entity, <span class="hljs-keyword">long</span> rowId)</span></span>;

    <span class="hljs-comment">/**
     * Returns the value of the primary key, if the entity has a single primary key, or, if not, null. Returns null if
     * entity is null.
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> K <span class="hljs-title">getKey</span><span class="hljs-params">(T entity)</span></span>;

    <span class="hljs-comment">/** Returns true if the Entity class can be updated, e.g. for setting the PK after insert. */</span>
    <span class="hljs-function"><span class="hljs-keyword">abstract</span> <span class="hljs-keyword">protected</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEntityUpdateable</span><span class="hljs-params">()</span></span>;

}
</code></pre>

                                
                                </section>
                            
    </div>
    <div class="search-results">
        <div class="has-results">
            
            <h1 class="search-results-title"><span class='search-results-count'></span> results matching "<span class='search-query'></span>"</h1>
            <ul class="search-results-list"></ul>
            
        </div>
        <div class="no-results">
            
            <h1 class="search-results-title">No results matching "<span class='search-query'></span>"</h1>
            
        </div>
    </div>
</div>

                        </div>
                    </div>
                
            </div>

            
                
                <a href="GreenDao使用.html" class="navigation navigation-prev navigation-unique" aria-label="Previous page: GreenDao使用">
                    <i class="fa fa-angle-left"></i>
                </a>
                
                
            
        
    </div>

    <script>
        var gitbook = gitbook || [];
        gitbook.push(function() {
            gitbook.page.hasChanged({"page":{"title":"GreenDao源码分析","level":"1.3","depth":1,"previous":{"title":"GreenDao使用","level":"1.2","depth":1,"path":"GreenDao使用.md","ref":"GreenDao使用.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["livereload"],"pluginsConfig":{"livereload":{},"highlight":{},"search":{},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"fontsettings":{"theme":"white","family":"sans","size":2},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"GreenDao源码分析.md","mtime":"2016-12-20T09:10:32.000Z","type":"markdown"},"gitbook":{"version":"3.2.0","time":"2016-12-20T06:34:16.286Z"},"basePath":".","book":{"language":""}});
        });
    </script>
</div>

        
    <script src="gitbook/gitbook.js"></script>
    <script src="gitbook/theme.js"></script>
    
        
        <script src="gitbook/gitbook-plugin-livereload/plugin.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search-engine.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-search/search.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/lunr.min.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-lunr/search-lunr.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-sharing/buttons.js"></script>
        
    
        
        <script src="gitbook/gitbook-plugin-fontsettings/fontsettings.js"></script>
        
    

    </body>
</html>

